#pragma once

#include "bmpeditor.h"
#include "spriteeditor.h"
#include "tabbedpanel.h"
#include "masterpanel.h"
#include "mixedbutton.h"
#include "icon_res.h"

class SpriteMonster : public MasterPanel
{
protected:
	/** the sprite editor (one, or zero) */
	SpriteEditor * m_spriteEdit;
	/** the bitmap editor(s) (potentially many, or zero) */
	TemplateVector<BMPEditor*> m_bmpEdit;
	/** the bitmap (and sprite editor) tabs */
	TabbedPanel m_tabbedContent;
	/** a list of all of the events passed into the app during the event gathering method */
	TemplateVector<SDL_Event> m_eventQueue;
	/** the button that triggers a new tab (load dialog, handles sprite or bitmap) */
	ImageButton m_addTab;

	// prototype
	bool addEditor(const char * a_path, const int & a_type);

	/** edits and manages a sprite */
	static const int EDITOR_SPRITE = ICON_SPRITE_FILE;
	/** edits and manages a bitmap */
	static const int EDITOR_BITMAP = ICON_IMAGE_FILE;
	/**
	 * is notified when an editor (Sprite or BMP) loads a new file
	 * @param {EDITOR_SPRITE, EDITOR_BITMAP}
	 */
	void notifyLoad(EditorPanel * a_editor, const int & a_type)
	{
		switch(a_type)
		{
			// when the sprite is loaded, it needs to check to see if it needs 
			// images that are currently loaded, and add those images to the sprite
		case EDITOR_SPRITE:
			// if the editorpanel is not the sprite editor, but it might be soon
			if(a_editor == m_spriteEdit || !m_spriteEdit)
			{
				SpriteEditor * e = (SpriteEditor*)a_editor;
				// how many images does the app currently have loaded?
				int hasImages = m_bmpEdit.size();
				// how many images does this sprite want?
				int wantsImages = e->getSprite()->getSourceImageCount();
				for(int i = 0; i < hasImages; ++i)
					addBMPToSprite(e->getSprite(), m_bmpEdit.get(i)->getBMP(), i);
				printf("sprite expects %d images\n", wantsImages);
				if(wantsImages > hasImages)
				{
					for(int i = 0; i < wantsImages-hasImages; ++i)
					{
						printf("attempting to add an image\n");
						// create a NULL BMP editor for each extra image required
//						addEditor(0, EDITOR_BITMAP);
					}
				}
			}
			break;
		case EDITOR_BITMAP:{
			int index = m_bmpEdit.indexOf((BMPEditor*)a_editor);
			// if the editorpanel is not in the bitmap list, then it probably will be soon.
			if(index == -1)index = m_bmpEdit.size();
			if(index >= 0)
			{
				BMPEditor * bmpeditor = (BMPEditor *)a_editor;
				addBMPToSprite(getSprite(), bmpeditor->getBMP(), index);
				bmpeditor->setClipPallette(m_spriteEdit->getClipPallette());
			}
			break;}
		}
	}
	/** notify spritemonster that a bitmap was loaded */
	static void notifyLoadBitMaP(void * a_sm, EditorPanel * a_editor){((SpriteMonster*)a_sm)->notifyLoad(a_editor,EDITOR_BITMAP);}
	/** notify spritemonster that a sprite was loaded */
	static void notifyLoadSprite(void * a_sm, EditorPanel * a_editor){((SpriteMonster*)a_sm)->notifyLoad(a_editor,EDITOR_SPRITE);}
	/** factory method for SpriteMonster editors */
	EditorPanel * createEditor(const int & a_type)
	{
		EditorPanel * p;
		EditorPanel::NOTIFY_LOAD n;
		switch(a_type)
		{
		case EDITOR_SPRITE:	p = new SpriteEditor();	n = notifyLoadSprite;	break;
		case EDITOR_BITMAP:	p = new BMPEditor();	n = notifyLoadBitMaP;	break;
		}
		if(p)p->setLoadNotifier(this, n);
		return p;
	}

	/**
	 * tells a sprite to update its' skins.
	 * @return true if everything is OK.
	 */
	bool addBMPToSprite(Sprite * s, BitMaP * bmp, const int & a_bmpEditorIndex)
	{
		char * errorsEncountered = 0;
		if(s && s->getSourceImageCount() > a_bmpEditorIndex)
		{
			errorsEncountered = s->replaceSourceImage(
				s->getSourceImage(a_bmpEditorIndex), bmp);
			if(errorsEncountered)
			{
				printf("error: %s\n", errorsEncountered);
			}
		}
		return errorsEncountered == 0;
	}
public:
	SpriteMonster():m_spriteEdit(0)
	{
		addChild(&m_tabbedContent);
	}

	/** @return the sprite being handled by the sprite editor */
	Sprite * getSprite(){return m_spriteEdit?m_spriteEdit->getSprite():0;}

	void setArea(const SRect & a_area)
	{
		ParentPanel::setArea(a_area);
		m_tabbedContent.setArea(a_area);
	}

	static void load(void * a_spriteMonster)
	{
		SpriteMonster * sm = (SpriteMonster*)a_spriteMonster;
		const int pathSize = 1024;
		char path[pathSize];
		EditorPanel::fileDialog("Load", ".", 0, path, pathSize, 0);
		int len = strlen(path);
		if(len)
		{
			char * ext = &path[EditorPanel::indexOfLetterLast(path, '.', len)];
			int extLen = strlen(ext);
			if(extLen > 1)
			{
				// ignore the '.'
				++ext;
				if(!strcmp("bmp", ext) || !strcmp("BMP", ext))
				{	sm->addEditor(path,EDITOR_BITMAP);	}
				// txt image (sprite file format)
				else if(!strcmp("txt", ext) || !strcmp("TXT", ext))
				{	sm->addEditor(path,EDITOR_SPRITE);}
				// unhandled type
				else{printf("cannot open extension type \"%s\".", ext);}
			}
		}
	}

	/**
	 * @param a_area how much space on the screen this SpriteMonster can take
	 */
	void init(const SRect & a_area)
	{
		m_addTab.setButtonImage(getImageClip(24));
		m_addTab.setParent(this);
		m_addTab.setAction(load, this);
		m_tabbedContent.addTab(&m_addTab);
		setArea(a_area);
	}

	void release()
	{
		for(int i = 0; i < m_bmpEdit.size(); ++i)
		{
			m_bmpEdit.get(i)->release();
			delete m_bmpEdit.get(i);
		}
		m_bmpEdit.release();
		if(m_spriteEdit){m_spriteEdit->release();delete m_spriteEdit;m_spriteEdit=0;}
		MasterPanel::release();
	}

	~SpriteMonster(){release();}

	/** handle all events */
	bool update(const int & a_ms)
	{
		bool change = false;
		for(int i = 0; i < m_eventQueue.size(); ++i)
		{
			change |= handleEvent(m_eventQueue.get(i));
		}
		m_eventQueue.clear();
		change |= m_tabbedContent.update(a_ms);
		return change;
	}

	/** do not handle all events when they are received by the hardware interupt. */
	void queueEvent(const SDL_Event & e){m_eventQueue.add(e);}
};